

import treemap.*;
import javax.swing.*;


// padding
static final int TREEMAP_PADDING = 15;
static final int TREEMAP_PADDING_TOP = 25;

static final int TREEMAP_WIDTH = 1200;
static final int TREEMAP_HEIGHT = 800;

static final int LEAF_COLOR_COUNT = 7;

color NONLEAF_COLOR = #cccccc;
color LEAF_COLORS[  ] = 
{
	#80b1d3,
	#ffffb3,
	#bebada,
	#fdb462,
	#b3de69,
	#fb8072,
	#fccde5
};

class NodeItem extends SimpleMapItem implements MapModel
{
	NodeItem parent;
	int level;
	Node node;
	
	MapLayout algorithm = new PivotBySplitSize();
	Mappable[] children;
	boolean layoutValid;
	boolean leftMost, rightMost;
	color fillColor;
	
	// box settings
	float boxLeft, boxRight, boxBottom, boxTop;

	public NodeItem(NodeItem parent, Node node, int level)
	{
		layoutValid = false;
		leftMost = false;
		rightMost = false;
		
		this.parent = parent;
		this.level = level;
		this.node = node;
		
		if (node.children.size() == 0)
		{
			size = 3;
		}
		else
		{
			size = 1;
		}
		// add all child nodes
		children = new Mappable[ node.children.size() ];
		for (int i = 0; i < node.children.size(); i++)
		{
			NodeItem newItem = new NodeItem(this, node.children.get(i), level+1);
			children[ i ] = newItem;
			size += newItem.getSize();
			
			if (i == 0) {
				newItem.leftMost = true;
			}
			else if (i == node.children.size() - 1) {
				newItem.rightMost = true;
			}
		}
	}
	
	void checkLayout()
	{
		if (!layoutValid)
		{
			if (getItemCount() != 0) {
				algorithm.layout(this, bounds);
			}
			layoutValid = true;
		}
	}

	void recursiveCalcBox()
	{
		boxLeft = x;
		boxRight = x + w;
			
		boxTop = y;
		boxBottom = y + h;
			
		if (parent != null)
		{
			if (boxLeft <= parent.boxLeft) {
				boxLeft = parent.boxLeft + TREEMAP_PADDING;
			}
			
			if (boxRight >= parent.boxRight) {
				boxRight = parent.boxRight - TREEMAP_PADDING;
			}
			
			if (boxTop <= parent.boxTop) {
				boxTop = parent.boxTop + TREEMAP_PADDING_TOP;
			}
			
			if (boxBottom >= parent.boxBottom) {
				boxBottom = parent.boxBottom - TREEMAP_PADDING;
			}	
		}
		for (int i = 0; i < children.length; i++) {
			( (NodeItem) children[i]).recursiveCalcBox();
		}
	}
	
	void doLayout()
	{
		if (getItemCount() != 0) {
			
			fillColor = NONLEAF_COLOR;
			algorithm.layout(this, bounds);
			for (int i = 0; i < children.length; i++) {
				( (NodeItem) children[i]).doLayout();
			}
		}
		else
		{
			// leaf
			int r = floor( random(LEAF_COLOR_COUNT) );
			fillColor =  LEAF_COLORS[ r ];
		}
	}
	
	void draw()
	{
		/*
		checkLayout();
		calcBox();
		*/

		pushStyle();
		
		if (children.length > 0) 
		{
			strokeWeight(2.5);
		}
		fill( fillColor );

		
		// draw myself
		rect(
			boxLeft,
			boxTop,
			boxRight,
			boxBottom 
		);
		
		// draw label
		fill(0);
		strokeWeight(2);
		if (children.length > 0)
		{
			textAlign(LEFT, TOP);
			text( node.txt, boxLeft + 5, boxTop + 5);
		}
		else
		{
			textAlign(CENTER, CENTER);
			text( node.txt, (boxLeft + boxRight) / 2, (boxTop + boxBottom) / 2 );
		}
		
		popStyle();
		
		for (int i = 0; i < children.length; i++)
		{
			// draw the child nodes
			children[i].draw();
		}
	}
	
	Mappable[] getItems() 
	{
		return children;
	}
	
	int getItemCount() {
		return children.length;
	}
}

class TreeMap
{
	NodeItem root;
	
	TreeMap(Node rootNode)
	{
		root = new NodeItem(null, rootNode, 0);
		root.setBounds(30, 30, TREEMAP_WIDTH, TREEMAP_HEIGHT);
		
		root.doLayout();
		root.recursiveCalcBox();
	}
	
	void draw()
	{
		noFill();
		stroke(0);
		strokeWeight(1.5);
		root.draw();
	}
}

